﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data;
using System.ComponentModel;
using System.Reflection;

namespace BusinessManagementStudio.Utilities
{
    public static class DatasetConversion
    {
        public static DataTable LinqQueryToDataTable<T>(IEnumerable<T> query)
        {
            DataTable tbl = new DataTable();
            PropertyInfo[] props = null;
            foreach (T item in query)
            {
                if (props == null) //尚未初始化
                {
                    Type t = item.GetType();
                    props = t.GetProperties();
                    foreach (PropertyInfo pi in props)
                    {
                        Type colType = pi.PropertyType;
                        //針對Nullable<>特別處理
                        if (colType.IsGenericType && colType.GetGenericTypeDefinition() == typeof(Nullable<>))
                        {
                            colType = colType.GetGenericArguments()[0];
                        }
                        //建立欄位
                        tbl.Columns.Add(pi.Name, colType);
                    }
                }
                DataRow row = tbl.NewRow();
                foreach (PropertyInfo pi in props)
                {
                    row[pi.Name] = pi.GetValue(item, null) ?? DBNull.Value;
                }
                tbl.Rows.Add(row);
            }
            return tbl;
        }

        ///// <summary>
        ///// (Overload) Extension method to convert a IEnumerable List<T> To a DataSet
        ///// </summary>
        ///// <typeparam name="T">List type that is being converted<typeparam>
        ///// <param name="list">The list itself that is being converted</param>
        ///// <param name="name">Name of the DataTable to be added to the DataSet</param>
        ///// <returns>A populated DataSet</returns>
        //public static DataSet ConvertGenericList<T>(this IEnumerable<T> list, string name)
        //{
        //    if (list == null)
        //        throw new ArgumentNullException("list");

        //    if (string.IsNullOrEmpty(name))
        //        throw new ArgumentNullException("name");

        //    DataSet converted = new DataSet(name);
        //    converted.Tables.Add(newTable(name, list));
        //    return converted;
        //}

        ///// <summary>
        ///// Extension method to convert a IEnumerable List<T> To a DataSet
        ///// </summary>
        ///// <typeparam name="T">List type that is being converted</typeparam>
        ///// <param name="list">The list itself that is being converted</param>
        ///// <returns>A populated DataSet</returns>
        //public static DataSet ConvertGenericList<T>(this IEnumerable<T> list)
        //{
        //    if (list == null)
        //        throw new ArgumentNullException("list");

        //    DataSet converted = new DataSet();
        //    converted.Tables.Add(newTable(list));
        //    return converted;
        //}

        ///// <summary>
        ///// (Overload) Method for getting and populating the DataTable that
        ///// will be in the converted DataSet
        ///// </summary>
        ///// <typeparam name="T">List type that is being converted</typeparam>
        ///// <param name="name">Name of the DataTable we want</param>
        ///// <param name="list">The list being converted</param>
        ///// <returns>A populated DataTable</returns>
        //private static DataTable newTable<T>(string name, IEnumerable<T> list)
        //{
        //    PropertyInfo[] pi = typeof(T).GetProperties();

        //    DataTable table = Table<T>(name, list, pi);

        //    IEnumerator<T> e = list.GetEnumerator();

        //    while (e.MoveNext())
        //        table.Rows.Add(newRow<T>(table.NewRow(), e.Current, pi));

        //    return table;
        //}

        ///// <summary>
        ///// Method for getting and populating the DataTable that
        ///// will be in the converted DataSet
        ///// </summary>
        ///// <typeparam name="T">List type that is being converted</typeparam>
        ///// <param name="list">The list being converted</param>
        ///// <returns>A populated DataTable</returns>
        //private static DataTable newTable<T>(IEnumerable<T> list)
        //{
        //    PropertyInfo[] pi = typeof(T).GetProperties();

        //    DataTable table = Table<T>(list, pi);

        //    IEnumerator<T> e = list.GetEnumerator();

        //    while (e.MoveNext())
        //        table.Rows.Add(newRow<T>(table.NewRow(), e.Current, pi));

        //    return table;
        //}

        ///// <summary>
        ///// Method for getting the data from the list then create a new
        ///// DataRow with the property values in the PropertyInfo being
        ///// provided, then return the row to be added to the Dataable
        ///// </summary>
        ///// <typeparam name="T">Type of the Generic list being converted</typeparam>
        ///// <param name="row">DatRow to populate and add</param>
        ///// <param name="listItem">The current item in the list</param>
        ///// <param name="pi">Properties for the current item in the list</param>
        ///// <returns>A populated DataRow</returns>
        //private static DataRow newRow<T>(DataRow row, T listItem, PropertyInfo[] pi)
        //{
        //    foreach (PropertyInfo p in pi)
        //        row[p.Name.ToString()] = p.GetValue(listItem, null);

        //    return row;
        //}

        ///// <summary>
        ///// (Overoad) Method resposible for the generation of the DataTable
        ///// </summary>
        ///// <typeparam name="T">Type of the List being converted</typeparam>
        ///// <param name="name">Name for the DataTable</param>
        ///// <param name="list">List being converted</param>
        ///// <param name="pi">Properties for the list</param>
        ///// <returns></returns>
        //private static DataTable Table<T>(string name, IEnumerable<T> list, PropertyInfo[] pi)
        //{
        //    DataTable table = new DataTable(name);

        //    foreach (PropertyInfo p in pi)
        //        table.Columns.Add(p.Name, p.PropertyType);

        //    return table;
        //}

        ///// <summary>
        ///// Method resposible for the generation of the DataTable
        ///// </summary>
        ///// <typeparam name="T">Type of the List being converted</typeparam>
        ///// <param name="list">List being converted</param>
        ///// <param name="pi">Properties for the list</param>
        ///// <returns></returns>
        //private static DataTable Table<T>(IEnumerable<T> list, PropertyInfo[] pi)
        //{
        //    DataTable table = new DataTable();

        //    foreach (PropertyInfo p in pi)
        //        table.Columns.Add(p.Name, p.PropertyType);

        //    return table;
        //}  
        public static DataSet ToDataSet<T>(this IList<T> list)
        {
            Type elementType = typeof(T);
            DataSet ds = new DataSet();
            DataTable t = new DataTable();
            ds.Tables.Add(t);

            //add a column to table for each public property on T
            foreach (var propInfo in elementType.GetProperties())
            {
                Type ColType = Nullable.GetUnderlyingType(propInfo.PropertyType) ?? propInfo.PropertyType;

                t.Columns.Add(propInfo.Name, ColType);
            }

            //go through each property on T and add each value to the table
            foreach (T item in list)
            {
                DataRow row = t.NewRow();

                foreach (var propInfo in elementType.GetProperties())
                {
                    row[propInfo.Name] = propInfo.GetValue(item, null) ?? DBNull.Value;
                }

                t.Rows.Add(row);
            }

            return ds;
        }
    }
}